/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pagoda.engine;

import java.util.UUID;
import javax.script.ScriptEngine;
import org.w3c.dom.Node;
import pagoda.util.StringUtil;
import pagoda.util.scripting.Expression;
import pagoda.util.scripting.ExpressionUtil;
import pagoda.util.scripting.Prototype;
import pagoda.util.scripting.PrototypeBindings;

/**
 *
 * @author Kevin Krohe
 */
public abstract class BaseTestAction implements TestAction {

    private TestEngine _testEngine;
    private ScriptEngine _scriptEngine;
    private PrototypeBindings _bindings
            = new PrototypeBindings();

    private TestAction _parent;
    private String _path;
    private String _name;
    private UUID _id;
    private boolean _enabled = true;
    private Expression<Boolean> _condition;

    public TestAction setParent(TestAction parent)
    {
        _parent = parent;
        setTestEngine(parent.getTestEngine());
        setPrototype(parent.getBindings());

        if(_scriptEngine == null)
            setScriptEngine(parent.getScriptEngine());

        return this;
    }

    public TestAction getParent()
    {
        return _parent;
    }

    public TestAction setEnabled(boolean enable) {
        _enabled = enable; return this;
    }

    public TestAction setCondition(Expression<Boolean> condition) {
        _condition = condition; return this;
    }

    public TestAction setId(UUID id) {
        _id = id; return this;
    }

    public UUID getId() {
        return _id;
    }

    public TestAction setName(String name) {
        _name = name; return this;
    }

    public String getName() {
        return _name;
    }

    public TestAction setPath(String path) {
        _path = path; return this;
    }

    public String getPath() {
        return _path;
    }

    public TestAction setTestEngine(TestEngine engine) {
        _testEngine = engine; return this;
    }

    public TestEngine getTestEngine() {
        return _testEngine;
    }

    public TestAction setScriptEngine(ScriptEngine engine) {
        _scriptEngine = engine; return this;
    }

    public ScriptEngine getScriptEngine() {
        if(_scriptEngine == null)
            _scriptEngine = ExpressionUtil.getDefaultScriptEngine();
        return _scriptEngine;
    }

    public TestAction setPrototype(Prototype bindings)
    {
        _bindings.setPrototype(bindings);
        return this;
    }

    public Prototype getBindings() {
        return _bindings;
    }

    public <T> Expression<T> buildExpression(String src)
    {
        if(StringUtil.IsNullOrEmpty(src))
            return null;
        return ExpressionUtil.build(
                getScriptEngine(),
                src,
                getBindings()
                );
    }

    public <T> Expression<T> buildExpression(Node xmlnode)
    {
        if(xmlnode == null)
            return null;
        return ExpressionUtil.build(
                getScriptEngine(),
                xmlnode,
                getBindings()
                );
    }


    public TestActionResult execute()
    {
        TestActionResult result = new TestActionResult();
        result.Status = TestActionStatus.NotRun;
        result.Message = null;
        result.ActionId = getId();
        try
        {
            boolean run = _enabled;
            if(_condition != null)
                run  = run && _condition.eval();
            if(run)
            {
                result.Status = TestActionStatus.Success;
                TestActionResult r = performAction();
                if(r != null)
                {
                    result.MergeSubResult(r);
                }
            }
        }
        catch(Throwable t)
        {
            result.Status = TestActionStatus.Error;
            result.Message = String.format(
                    "Failed to execute action '%s' : %s\n%s",
                    getName(),
                    t.getMessage(),
                    t
                    );
        }
        if(result.Status.compareTo(TestActionStatus.NotRun) > 0)
            _testEngine.processResult(result);
        return result;
    }

    protected abstract TestActionResult performAction();
}
